﻿\section{绪论}

计算机深刻地改变了人们的生产生活方式。
操作系统是应用程序和计算机硬件之间的中间层，管理和协调计算机中所有的软硬件资源，是一切应用程序的基石。
操作系统横跨软硬件世界，对操作系统基本原理的理解和把握能够使程序设计人员对程序设计艺术产生更加深刻的理解和认识，从硬件视角理解程序是怎样被转化为一条条最简单的机器指令由底层硬件一步步执行进而完成一项庞大任务的。
具体的操作系统实现随着时代的进步和发展不断地改进，但是操作系统基本的概念和设计思想自操作系统诞生以来却未曾产生大的变动。

操作系统通过 \textbf{虚拟化（Virtualization）} 将磁盘等硬件设备抽象为一组用户程序很容易使用的系统调用接口，屏蔽了底层硬件之间细节，解除了用户程序与硬件之间的耦合，这种思想贯穿于现代软件工程的始终。
\textbf{并发性（Concurrency）} 是操作系统的根本属性，因为只要有操作系统的存在，就必然有与其相对的用户程序。
用户程序和操作系统内核程序之间的切换产生出最早的并发概念。
操作系统中对并发的控制催生了并行计算，使计算机解决问题的速度获得了质的飞跃。
存储程序冯·诺依曼体系结构的核心思想，操作系统通过将磁盘等设备封装为文件系统，提供 \textbf{持久化（Persistence）} 功能，将程序及其所需数据以一种对用户透明的方式存储在磁盘设备上。\cite{3ezpcs}

理解操作系统的运行原理和基本设计思想，不仅需要在宏观角度认识和理解操作系统，更需要立足于操作系统实现细节的基础上进行思想的拔高，才能体会到程序设计艺术的奥妙。
本设计以实现一个计算机启动到内核装载执行为线索，尝试实现一个简易的操作系统内核，试图从程序设计人员的视角厘清操作系统概念。


\subsection{设计目标}

本项目旨在基于 Intel IA-32 体系结构 \cite{ia32}\cite{amd64}（32 位）处理器 \footnote{ 本文使用 x86 代指 32 位 IA-32 体系结构，x64 代指 64 位 AMD64/IA-32e 体系结构。
} 实现名为 Simple 的操作系统。


\subsection{论文结构安排}

第一章，绪论。介绍本操作系统开发目标、使用的工具链及文中涉及 x86 体系结构的术语约定。

第二章，内核的装载、引导和运行。本章分析操作系统内核所需的运行环境，并为操作系统构建引导，编写操作系统内核运行必需的函数库。
然后，简要介绍操作系统内核开发常用的调试手段。

第三章，中断和异常事件处理。介绍 x86 体系结构对中断和异常事件的处理方式，并基于 8259A 实现操作系统内核的中断处理模块。

第四章，内存管理。在内存分页的基础上，实现请求分页、栈内存管理和对缺页故障的处理，随后通过引入内存堆描述符的结构实现堆内存管理。

第五章，线程、进程的设计与实现。在内核中构建线程控制块结构实现线程的创建和调度，并通过创建进程控制块实现以进程位单位进行资源的管理和分配。
通过 x86 提供的中断机制，将操作系统 API 封装为系统调用供用户进程使用。

第六章，文件系统。基于 Microsoft FAT32 格式规范实现文件系统。

第七章，总结。主要讨论本操作系统实现中尚可改进之处。

\subsection{开发环境简述}

本项目使用 x86 汇编语言和 C 语言进行内核开发。
采用 LLVM（Low Level Virtual Machine）工具链作为 C 语言开发工具。
本设计实现的操作系统在 x86 模拟器平台上完成调试和验证，Bochs 模拟器（Bochs Emulator）\cite{bochs-doc} 与其自带的 \verb{bochsdbg}（Bochs Debugger）结合使用，完成对操作系统引导程序的调试验证；QEMU（Quick Emulator）\cite{qemu-doc} 与 GNU/GDB（GNU Debugger）\cite{gdb-doc} 及 LLVM-LLDB（Low Level Debugger for LLVM）\cite{lldb-doc} 结合使用，用以完成对操作系统内核的调试验证。

项目中使用的开发工具罗列如下：

\begin{itemize}
    \item 虚拟平台：Bochs、QEMU
    \item x86 汇编器：NASM （Netwide Assembler）
    \item C 语言编译器：LLVM-Clang（C language family frontend for LLVM）
    \item 链接器：LLVM-LLD（LLVM Linker）
    \item 调试器：\verb{bochsdbg}、GNU/GDB、LLVM-LLDB
    \item 构建工具：GNU/Make\cite{gnumake-doc}
    \item 项目管理工具：GNU/Git
    \item 脚本语言：Powershell\cite{pwsh-doc}
\end{itemize}

\subsection{x86 体系结构概述}

\subsubsection{x86 处理器约定}

    \begin{itemize}
        \item \textbf{字节、字、双字、四字}：\textbf{字节} 是 Intel x86 体系结构下数据存放的基本单位，其大小为 8 位二进制数。
Intel 8086 的机器字长为两字节，为保持向下兼容，Intel 系列处理器将两字节的数据大小称作 \textbf{字（WORD）}。
引入 32 位处理器后，将四字节的数据大小称作 \textbf{双字（DWORD）}，在 64 位处理器中又将八字节的数据大小称作 \textbf{四字（QWORD）}。
x86 支持按字节寻址、按字寻址、按双字寻址三种不同的寻址方式，x64 在 x86 基础上增加了按四字寻址。

        \item \textbf{字节序}： x86/x64 使用 \textbf{小端方式} 存放数据，字、双字、四字中的字节按照权重由低到高排布，低地址存放权重低的字节，高地址存放权重高的字节。

        \item \textbf{实模式（Real Mode）}：Intel 8086 处理器访问内存直接使用内存物理地址，该处理器拥有 16 位机器字长和 20 位的地址线，故拥有 \MiB{1} 的寻址空间。
Intel 后续 x86 系列处理器为兼容 Intel 8086 而引入实模式，实模式下处理器访问的内存地址均为内存的物理地址，实模式下的 x86 处理器第 20 根地址线（称作 \lstinline{A20}）处于关闭状态，因而最多允许访问 \MiB{1} 的物理地址空间。

        \item \textbf{保护模式（Protected Mode）}：Intel 8086 处理器缺少对内存访问的保护措施。
Intel 80286 处理器在 Intel 8086 的基础上引入了保护模式，并在 Intel 80386 处理器中进一步完善，以提供对内存访问的保护。

        \item \textbf{分段模型（Segmented Model）}：使用 Intel 系列处理器时，须由设计者将内存空间划分为若干块寻址空间，每块寻址空间被称作 \textbf{段（Segment）}。
访问内存时，需要指明访问的段及段内偏移，该种内存模型被称作 \textbf{分段模型}。
x86 中的段可被细分为非系统段和系统段，非系统段中存放数据（被称作数据段）或指令（被称作指令段）；系统段有专门用途，如 \textbf{门（Gate）} 就是一类特殊的系统段，后续章节在使用系统段时将详细介绍。

        \item \textbf{段描述符（Segment Descriptor）、段选择子（Segment Selector）} x86 使用段描述符描述某个内存段的信息，段描述符也被简称为描述符。
段选择子用于选中某个段描述符，在访问内存段时，需要在段寄存器中保存段选择子。

        \item \textbf{平坦模型（Flat Model）}：与分段模型相对，平坦模型下所有的内存单元均位于同一块寻址空间。
x86 处理器在保护模式下可使用 \textbf{基本平坦模型（Basic Flat Model）} 方案实现平坦模型。

    \end{itemize}

\subsubsection{x86 体系结构发展历史}

Intel 8086 和 Intel 8088 处理器是 x86 体系结构发展早期的产品。
Intel 8086/8088 处理器拥有 16 位的机器字长，提供 20 根地址线，允许按字节（8 位）寻址和按字（16 位）寻址，这意味着 Intel 8086/8088 处理器最多可访问 \MiB{1} 的内存空间。
Intel 8086/8088 处理器提供 8 个 16 位的通用寄存器，但由于需要 20 位地址访存，因而 8086/8088 处理器中引入了内存分段的概念。
除了通用寄存器，Intel 8086/8088 处理器还提供 5 个段寄存器，访存地址由段地址和段内偏移地址（亦称有效地址）构成。
由段寄存器中保存的段地址左移 4 位后与有效地址相加后得到物理内存地址送入地址线访问内存单元。


Intel 8086/8088 处理器访存所用的地址全部为物理地址，没有任何的保护措施，在后续的处理器系列中这种访存的模式被称作实模式（Real Mode）。
Intel 80286 处理器将地址线宽度扩充为 24 位，并且还在 Intel 80386/8088 的基础上引入了保护模式（Protected Mode）的概念，保护模式中对段增设了如下机制：

\begin{itemize}
    \item 段界限检查
    \item 只读 / 只运行段选项
    \item 特权级
\end{itemize}

Intel 80286 中，每个段被赋予一定的属性，包括段的基址、段的界限。
Intel 286 处理器还引入了特权级的概念。
特权级共分为四级，特权级数值越小代表特权级越高。
一个段要访问另一个段，必须要确保两个段的特权级匹配。
Intel 286 处理器还为每个段设置只读 / 只运行属性字段。
这些属性被存放在段描述符（Segment Descriptor）的结构中，若干个这样的段描述符连续存放在内存中，构成一张描述符表（Descriptor Table）。
访问某个段时，需要指定段选择子（Segment Selector）。
段选择子作为描述符表的索引，处理器根据段选择子从描述符表中取出描述符，经过保护机制检查后才进行对段的访问。


Intel 80286 还提供了基于分段交换的虚拟内存管理机制，虚拟内存管理机制后来进一步发展为内存分页管理机制。


Intel 80386 处理器将机器字长提升到了 32 位，对应地 8 个通用寄存器宽度也被提升到了 32 位。
为了保持向下兼容，Intel 386 中提供了 3 种运行模式：实模式、保护模式、虚拟 8086 模式。
Intel 386 及其之后的处理器系列基本都兼容这 3 种运行模式。
其中，实模式是 Intel 386 处理器上电后的初始模式（兼容 Intel 8086/8088），通过正确设置描述符表和控制寄存器，可从实模式进入 16 位保护模式（兼容 Intel 80286）或 32 位保护模式。
虚拟 8086 模式在 32 位保护模式下虚拟出 \MiB{1} 的内存空间，用于在 32 位模式下高效的运行工作于 16 位实模式下的程序。


Intel 80286 及其之前的处理器中，对于寄存器的使用有着较为严格的限制。
只有 \lstinline{BX} 可用于基址寻址，只有 \lstinline{SI} 和 \lstinline{DI} 可用于变址寻址，\lstinline{BP} 和 \lstinline{SP} 专用于堆栈的选址。
也即可用于寻址的寄存器不包含 \lstinline{AX}、\lstinline{CX}、\lstinline{DX}。
Intel 80386 及其之后的处理器除了扩展了处理器的字长，同时还允许所有的通用寄存器用于寻址。
扩展后的寄存器，如 \lstinline{EAX}，可在实模式下直接使用。


Intel 80386 进一步发展了虚拟内存管理，引入了分页机制。
此外，由于 Intel 386 中的通用寄存器宽度达到了 32 位，与地址线宽度一致，因此在后续的 x86 操作系统设计中，平坦模型（Flat Model）取代了传统的分段内存模型（Segmented-Memory Model）成为主流。
平坦模型结合分页内存机制，共同构成了现代 x86 操作系统内存管理体系的基础。


由于 Intel 80386 的后续系列 32 位处理器产品均以 Intel 386 为原型，因此这些后续系列的处理器常以 i386 作为代称。


本操作系统设计针对 32 位的 IA-32 架构处理器平台，因此对于从 IA-32 架构扩展而来的 AMD64/IA-32e 不做过多讨论。
